<

「ゾーンが一致しません」メッセージ

まとめ

Flutter 3.10 以降、フレームワークは不一致を検出します ゾーンを使用する場合、デバッグ ビルドでゾーンをコンソールに報告します。

バックグラウンド

ゾーンは、Dart でコールバックを管理するためのメカニズムです。 主にオーバーライドに役立ちますが、printTimerテストのロジック、 テストでのエラーを見つけるために、 グローバル変数のスコープ設定に使用されることもあります アプリケーションの特定の部分に。

Flutter には必要なものがあります (そしてこれまでも常に必要でした) すべてのフレームワーク コードが同じゾーンで実行されるようにします。 特に、これは次の呼び出しを意味します。WidgetsFlutterBinding.ensureInitialized()同じゾーンで実行する必要があります への呼び出しとしてrunApp()

これまで、Flutter はそのような不一致を検出していませんでした。 これにより、不明瞭でデバッグが困難な問題が発生することがあります。 例えば、 キーボード入力のコールバックが呼び出される可能性があります にアクセスできないゾーンを使用するzoneValuesそれが期待していること。 私たちの経験では、 ゾーンを使用するすべてのコードではないにしても、ほとんどのコード のすべての部分が保証されるわけではありません。 Flutter フレームワークは同じゾーンで動作しています 潜在的なバグがあります。 多くの場合、これらのバグはゾーンの使用とは無関係に見えます。

この不変条件に誤って違反した開発者を助けるために、 Flutter 3.10 以降、 不一致が検出された場合、デバッグ ビルドで致命的ではない警告が出力されます。 警告は次のようになります。

════════ Exception caught by Flutter framework ════════════════════════════════════
The following assertion was thrown during runApp:
Zone mismatch.

The Flutter bindings were initialized in a different zone than is now being used.
This will likely cause confusion and bugs as any zone-specific configuration will
inconsistently use the configuration of the original binding initialization zone or
this zone based on hard-to-predict factors such as which zone was active when a
particular callback was set.
It is important to use the same zone when calling `ensureInitialized` on the
binding as when calling `runApp` later.
To make this warning fatal, set BindingBase.debugZoneErrorsAreFatal to true before
the bindings are initialized (i.e. as the first statement in `void main() { }`).
[...]
═══════════════════════════════════════════════════════════════════════════════════

この警告は次のような場合に致命的になる可能性があります。 設定BindingBase.debugZoneErrorsAreFataltrue。 このフラグはデフォルトに変更される可能性があります。trueFlutter の将来のバージョンで。

移行ガイド

このメッセージを沈黙させる最善の方法は、 アプリケーション内からゾーンの使用を削除します。 ゾーンのデバッグは非常に難しい場合があります。 これらは本質的にグローバル変数であるため、 そしてカプセル化を破ります。 ベスト プラクティスは、グローバル変数とゾーンを避けることです。

ゾーンを削除できない場合 (たとえば、アプリケーションがサードパーティのライブラリに依存しているため) 構成がゾーンに依存している)、 次に、Flutter フレームワークへのさまざまな呼び出し すべて同じゾーンに移動する必要があります。 通常、これは通話を次の場所に移動することを意味します。WidgetsFlutterBinding.ensureInitialized()に への呼び出しと同じクロージャrunApp()

これは、ゾーンが次の場合に厄介になる可能性があります。runApp実行されます で初期化されていますzoneValuesプラグインから取得した (これには必要ですWidgetsFlutterBinding.ensureInitialized()呼ばれたこと)。

この種のシナリオにおける 1 つのオプションは、 可変オブジェクトをzoneValues、 と 値が利用可能になったら、そのオブジェクトをその値で更新します。

import 'dart:async';
import 'package:flutter/material.dart';

class Mutable<T> {
  Mutable(this.value);
  T value;
}

void main() {
  var myValue = Mutable<double>(0.0);
  Zone.current.fork(
    zoneValues: {
      'myKey': myValue,
    }
  ).run(() {
    WidgetsFlutterBinding.ensureInitialized();
    var newValue = ...; // obtain value from plugin
    myValue.value = newValue; // update value in Zone
    runApp(...);
  });
}

使用する必要があるコード内でmyKey、 を使用して間接的に取得できますZone.current['myKey'].value

このような解決策がうまくいかない場合 サードパーティの依存関係により使用が必要となるため、 特定のタイプの、特定のzoneValues鍵、 依存関係へのすべての呼び出しは、 包まれたZone適切な値を提供する呼び出し。

この方法でゾーンを使用するパッケージを使用することを強くお勧めします。 より保守しやすいソリューションに移行します。

タイムライン

リリースされたバージョン: 3.9.0-9.0.pre
安定リリース: 3.10.0

参考文献

API ドキュメント:

  • Zone
  • BindingBase.debugZoneErrorsAreFatal

関連する問題:

  • 問題 94123: Flutter フレームワークは、ensureInitialized の場合に警告を出しません runApp とは別のゾーンで呼び出されます

関連する PR:

  • PR 122836: runApp が呼び出されることをアサートします binding.ensureInitialized と同じゾーン内